package com.iwhale.zcm.utils;

import java.io.InputStream;
import java.io.PushbackInputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;

public class MultiMemberGZIPInputStream extends GZIPInputStream {
    /**
     * Creates a new instance.
     *
     * @param in   The input stream.
     * @param size The buffer size.
     * @throws IOException if an IO exception occurs.
     */
    public MultiMemberGZIPInputStream(InputStream in, int size) throws IOException {
        super(new PushbackInputStream(in, size), size);
        this.size = size;
    }

    /**
     * Creates a new instance.
     *
     * @param in The input stream.
     * @throws IOException if an IO exception occurs.
     */
    public MultiMemberGZIPInputStream(InputStream in) throws IOException {
        super(new PushbackInputStream(in, 1024));
        this.size = -1;
    }

    private MultiMemberGZIPInputStream(MultiMemberGZIPInputStream parent)
            throws IOException {
        super(parent.in);
        this.size = -1;
        if (parent.parent == null) {
            this.parent = parent;
        } else {
            this.parent = parent.parent;
        }
        this.parent.child = this;
    }

    private MultiMemberGZIPInputStream(MultiMemberGZIPInputStream parent,
                                       int size) throws IOException {
        super(parent.in, size);
        this.size = size;
        if (parent.parent == null) {
            this.parent = parent;
        } else {
            this.parent = parent.parent;
        }
        this.parent.child = this;
    }

    private MultiMemberGZIPInputStream parent;
    private MultiMemberGZIPInputStream child;
    private int size;
    private boolean eos;


    @Override
    public int read(byte[] inputBuffer, int inputBufferOffset,
                    int inputBufferLen) throws IOException {
        if (eos) {
            return -1;
        }
        if (this.child != null) {
            return this.child.read(inputBuffer, inputBufferOffset,
                    inputBufferLen);
        }

        int charsRead = super.read(inputBuffer, inputBufferOffset,
                inputBufferLen);
        if (charsRead == -1) {
            int n = inf.getRemaining() - 8;
            if (n > 0) {
                ((PushbackInputStream) this.in).unread(buf, len - n, n);
            } else {
                byte[] b = new byte[1];
                int ret = in.read(b, 0, 1);
                if (ret == -1) {
                    eos = true;
                    return -1;
                } else {
                    ((PushbackInputStream) this.in).unread(b, 0, 1);
                }
            }

            MultiMemberGZIPInputStream tmpChild;
            if (this.size == -1) {
                tmpChild = new MultiMemberGZIPInputStream(this);
            } else {
                tmpChild = new MultiMemberGZIPInputStream(this, this.size);
            }
            return tmpChild.read(inputBuffer, inputBufferOffset, inputBufferLen);
        } else {
            return charsRead;
        }
    }

}
